---
title: Value semantics
sidebar_position: 2
description: An explanation of Mojo's value-semantic defaults.
---

Mojo doesn't enforce value semantics or reference semantics. It supports them
both and allows each type to define how it is created, copied, and moved (if at
all). So, if you're building your own type, you can implement it to support
value semantics, reference semantics, or a bit of both. That said, Mojo is
designed with argument behaviors that default to value semantics, and it
provides tight controls for reference semantics that avoid memory errors.

The controls over reference semantics are provided by the [value ownership
model](/mojo/manual/values/ownership), but before we get into the syntax
and rules for that, it's important that you understand the principles of value
semantics. Generally, it means that each variable has unique access to a value,
and any code outside the scope of that variable cannot modify its value.

## Intro to value semantics

In the most basic situation, sharing a value-semantic type means that you create
a copy of the value. This is also known as "pass by value." For example,
consider this code:

```mojo
def main():
    var x = 1
    var y = x
    y += 1

    print("x:", x)
    print("y:", y)
```

```output
x: 1
y: 2
```

We assigned the value of `x` to `y`, which creates the value for `y` by making a
copy of `x`. When we increment `y`, the value of `x` doesn't change. Each
variable has exclusive ownership of a value.

Whereas, if a type instead uses reference semantics, then `y` would point to
the same value as `x`, and incrementing either one would affect the value for
both. Neither `x` nor `y` would "own" the value, and any variable would be
allowed to reference it and mutate it.

Numeric values in Mojo are value semantic because they're trivial types, which
are cheap to copy.

## Value semantics in Mojo functions

Value semantics also apply to function arguments in Mojo by default. However,
the way in which they apply differs depending on the [argument
convention](/mojo/manual/values/ownership#argument-conventions), which is
discussed in the [Ownership](/mojo/manual/values/ownership) page.

For example, in the following function, the `y` argument is immutable by
default, so if the function wants to modify the value in the local scope, it
needs to make a local copy:

```mojo
fn add_two(y: Int):
    # y += 2  # This would cause a compiler error because `y` is immutable
    # We can instead make an explicit copy:
    var z = y
    z += 2
    print("z:", z)

def main():
    var x = 1
    add_two(x)
    print("x:", x)
```

```output
z: 3
x: 1
```

This is all consistent with value semantics because each variable maintains
unique ownership of its value.

The way the function receives the `y` value is a "look but don't touch"
approach to value semantics. This is also a more memory-efficient approach when
dealing with memory-intensive arguments, because Mojo doesn't make any copies
unless we explicitly make the copies ourselves.

Thus, the default behavior for function arguments is fully value
semantic: arguments are immutable references, and any living
variable from the caller is not affected by the function.

But we must also allow reference semantics (mutable references) because it's
how we build performant and memory-efficient programs (making copies of
everything gets really expensive). The challenge is to introduce reference
semantics in a way that does not disturb the predictability and safety of value
semantics.

The way we do that in Mojo is, instead of enforcing that every variable have
"exclusive access" to a value, we ensure that every value has an "exclusive
owner," and destroy each value when the lifetime of its owner ends.

On the next page about [value ownership](/mojo/manual/values/ownership), you'll
learn how to modify the default argument conventions, and safely use reference
semantics so every value has only one owner at a time.
